package com.ruoyi.system.service.impl;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.es.domain.EsDeviceDataInfo;
import com.ruoyi.es.domain.EsDeviceInfo;
import com.ruoyi.es.domain.EsValueInfo;
import com.ruoyi.es.mapper.EsDeviceDataInfoMapper;
import com.ruoyi.es.mapper.EsDeviceInfoMapper;
import com.ruoyi.es.mapper.EsValueInfoMapper;
import com.ruoyi.system.domain.BuildingDataBoard;
import com.ruoyi.system.domain.Forest.IotDeviceInfo;
import com.ruoyi.system.domain.Forest.IotPage;
import com.ruoyi.system.domain.Forest.IotResult;
import com.ruoyi.system.domain.Forest.second.BaseResult;
import com.ruoyi.system.domain.Forest.second.DeviceListResult;
import com.ruoyi.system.domain.Forest.second.PageResult;
import com.ruoyi.system.domain.Forest.second.ValueResult;
import com.ruoyi.system.domain.HouseDataBoard;
import com.ruoyi.system.domain.cache.DeviceCache;
import com.ruoyi.system.domain.result.IotDeviceBindResult;
import com.ruoyi.system.service.DeviceAsyncClient;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.SecondDeviceAsyncClient;
import org.checkerframework.checker.units.qual.A;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.script.AggregationScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedTopHits;
import org.elasticsearch.search.aggregations.metrics.TopHits;
import org.elasticsearch.search.aggregations.pipeline.BucketScriptPipelineAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.BucketSelectorPipelineAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysDeviceMapper;
import com.ruoyi.system.domain.SysDevice;
import com.ruoyi.system.service.ISysDeviceService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.Null;

/**
 * 设备Service业务层处理
 * 
 * @author ruoyi
 * @date 2024-08-07
 */
@Service
public class SysDeviceServiceImpl implements ISysDeviceService 
{
    @Autowired
    private SysDeviceMapper sysDeviceMapper;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private RedisCache redisCache;

//    @Resource
//    private DeviceAsyncClient deviceAsyncClient;

//    @Autowired
//    private EsDeviceInfoMapper esDeviceInfoMapper;

    @Autowired
    private EsDeviceDataInfoMapper esDeviceInfoMapper;



    @Resource
    private SecondDeviceAsyncClient secondDeviceAsyncClient;
    @Autowired
    private EsValueInfoMapper esValueInfoMapper;

    /**
     * 校验设备code是否已导入
     * @param deviceCodeList
     * @return
     */
    @Override
    public List<IotDeviceBindResult> checkDeviceCodeImport(List<String> deviceCodeList){

        List<String> deviceCodeListNotExists = sysDeviceMapper.checkDeviceCodeNotExists(deviceCodeList);
        return deviceCodeList.stream().map(deviceCode -> {
            IotDeviceBindResult iotDeviceBindResult = new IotDeviceBindResult();
            iotDeviceBindResult.setDeviceCode(deviceCode);
            iotDeviceBindResult.setIsImport(deviceCodeListNotExists.contains(deviceCode) ? 0 : 1);
            return iotDeviceBindResult;
        }).collect(Collectors.toList());
    }
    /**
     * 记录设备日志
     * @param logInfo
     * @param deptId
     */
    @Override
    public void logDeviceInfo(EsDeviceInfo logInfo, String  deptId){
//        esDeviceInfoMapper.insert(logInfo, IotConstants.IOT_DEVICE_TABLE_NAME + deptId);
    }

    /**
     * 记录设备日志
     * @param logInfo
     * @param deptId
     */
    @Override
    public void secondLogDeviceInfo(EsDeviceDataInfo logInfo, String  deptId){
        esDeviceInfoMapper.insert(logInfo, IotConstants.IOT_DEVICE_TABLE_NAME + deptId);
    }

    /**
     * 记录阀门日志
     * @param logInfo
     * @param deptId
     */
    @Override
    public void logValueInfo(EsValueInfo logInfo, String  deptId){
        esValueInfoMapper.insert(logInfo, IotConstants.IOT_VALUE_TABLE_NAME + deptId);
    }
    /**
     * 统计数据
     * @param deptId
     * @return
     */
    @Override
    public Double selectDeviceInfoAgg(Long deptId, String colum){
        LambdaEsQueryWrapper<EsDeviceDataInfo> wrapper = new LambdaEsQueryWrapper<>();
        wrapper.indexName(IotConstants.IOT_DEVICE_TABLE_NAME + deptId);
        wrapper.size(0);
        // RestHighLevelClient原生语法
        SearchSourceBuilder searchSourceBuilder = esDeviceInfoMapper.getSearchSourceBuilder(wrapper);
        AggregationBuilder aggregation = AggregationBuilders.terms("devices").field("deviceId").size(IotConstants.ELASTICSEARCH_MAX);
        AggregationBuilder subAggregation = AggregationBuilders.topHits("last_report").size(1)
                .fetchSource(colum,"").sort("timestamp", SortOrder.DESC);
        aggregation.subAggregation(subAggregation);
        searchSourceBuilder.aggregation(aggregation);
        wrapper.setSearchSourceBuilder(searchSourceBuilder);
        SearchResponse esResponse = esDeviceInfoMapper.search(wrapper);
        // 解析聚合结果
        ParsedLongTerms latestPerDeviceTerms = esResponse.getAggregations().get("devices");
        double totalValue = 0.0;
        for (Terms.Bucket bucket : latestPerDeviceTerms.getBuckets()) {
            TopHits topHits = bucket.getAggregations().get("last_report");
            SearchHit hit = topHits.getHits().getAt(0);
            double tempIntake = ((Number)hit.getSourceAsMap().get(colum)).doubleValue();
            totalValue += tempIntake; // 累加所有设备的温度
        }
        return totalValue;
    }
    /**
     * 查询设备
     * 
     * @param deviceId 设备主键
     * @return 设备
     */
    @Override
    public SysDevice selectSysDeviceByDeviceId(Long deviceId)
    {
        return sysDeviceMapper.selectSysDeviceByDeviceId(deviceId);
    }

    /**
     * 同步设备历史数据
     * @param deviceCode
     */
    @Override
    public void syncHistoryDevice(String deviceCode){
        redisCache.setCacheObject(CacheConstants.SYNC_DEVICE,"true");
//        SysDevice device = selectSysDeviceByDeviceCode(deviceCode);
//        Date now = DateUtils.getNowDate();
//        String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, now);
//        String startTime = DateUtils.getDayByDeal(now, -100 , DateUtils.YYYY_MM_DD_HH_MM_SS);
//        Date startDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS,startTime);
//        Date stopDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, "2023-01-01 00:00:00");
/*
        while (startDate.after(stopDate)){
            endTime = startTime;
            startTime = DateUtils.getDayByDeal(startDate, -100 , DateUtils.YYYY_MM_DD_HH_MM_SS);
            startDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS,startTime);
            int page = 1;
            IotResult<IotPage<IotDeviceInfo>>  result = deviceAsyncClient.getDeviceHistory(deviceCode,page,100,startTime, endTime);
            if (result.getCode() == 0){
                IotPage<IotDeviceInfo> iotPage = result.getData();
                // 判断是否还有下一页
                if (iotPage.getCurrent() >= iotPage.getPages()){
                    continue;
                }else {
                    page ++;
                }
                for (IotDeviceInfo iotDeviceInfo : iotPage.getRecords()){
                    EsDeviceInfo logInfo = new EsDeviceInfo();
                    BeanUtils.copyProperties(iotDeviceInfo, logInfo);
                    logInfo.setDeptId(device.getDeptId());
                    logInfo.setDeviceId(device.getDeviceId());
                    logInfo.setDeviceCode(device.getDeviceCode());
                    logInfo.setCreateTime(now);
                    if (iotDeviceInfo.getDeviceClock() == null){
                        logInfo.setDeviceClock(now);
                    }else {
                        logInfo.setDeviceClock(iotDeviceInfo.getDeviceClock());
                    }
                    logDeviceInfo(logInfo, String.valueOf(device.getDeptId()));
                }
            }

        }

//        System.out.println(result);

 */
        redisCache.setCacheObject(CacheConstants.SYNC_DEVICE,"false");
    }
    /**
     * 通过设备code 查询设备信息
     * @param deviceCode
     * @return
     */
    @Override
    public SysDevice selectSysDeviceByDeviceCode(String deviceCode, Long deptId){
        return sysDeviceMapper.selectSysDeviceByDeviceCode(deviceCode, deptId, null, null);
    }
    /**
     * 查询设备列表
     * 
     * @param sysDevice 设备
     * @return 设备
     */
    @Override
    public List<SysDevice> selectSysDeviceList(SysDevice sysDevice)
    {
        return sysDeviceMapper.selectSysDeviceList(sysDevice);
    }

    /**
     * 新增设备
     * 
     * @param sysDevice 设备
     * @return 结果
     */
    @Override
    public int insertSysDevice(SysDevice sysDevice)
    {
        sysDevice.setCreateTime(DateUtils.getNowDate());
        return sysDeviceMapper.insertSysDevice(sysDevice);
    }


    @Override
    @Transactional
    public void syncDevice(String username, Long deptId) {
        redisCache.setCacheObject(CacheConstants.SYNC_DEVICE,"true");

        int page = 1;
        while (true){
            BaseResult<PageResult<DeviceListResult>> secondResult = secondDeviceAsyncClient.getDeviceList(page, 50);
            if (secondResult.getCode() != 200){
                break;
            }
            PageResult<DeviceListResult> data = secondResult.getData();
            if (data.getItems().isEmpty()){
                break;
            }
            Map<String, DeviceListResult> deviceMap = data.getItems().stream().collect(Collectors.toMap(DeviceListResult ::getNodeId, Function.identity()));

            List<String> deviceCodeList = new ArrayList<>(deviceMap.keySet());
            List<String> deviceCodeListNotExists = sysDeviceMapper.checkDeviceCodeNotExists(deviceCodeList);
            for (String deviceCode : deviceCodeListNotExists){
                DeviceListResult iotDeviceInfo = deviceMap.get(deviceCode);
                SysDevice sysDevice = SysDevice.of(iotDeviceInfo);
                sysDevice.setCreateBy(username);
                sysDevice.setDeptId(deptId);
                sysDeviceMapper.insertSysDevice(sysDevice);
            }
            if (page < data.getTotalPage()){
                page ++;
            } else {
                break;
            }
            /*
             IotResult<IotPage<IotDeviceInfo>> result = deviceAsyncClient.getDeviceList(page, 100);
             IotPage<IotDeviceInfo> iotPage = result.getData();
             if (iotPage.getRecords().isEmpty()){
             break;
             }
             Map<String, IotDeviceInfo> deviceMap = iotPage.getRecords().stream().collect(Collectors.toMap(IotDeviceInfo ::getDeviceCode, Function.identity()));
             List<String> deviceCodeList = new ArrayList<>(deviceMap.keySet());
             List<String> deviceCodeListNotExists = sysDeviceMapper.checkDeviceCodeNotExists(deviceCodeList);
             for (String deviceCode : deviceCodeListNotExists){
             IotDeviceInfo iotDeviceInfo = deviceMap.get(deviceCode);
             SysDevice sysDevice = SysDevice.of(iotDeviceInfo);
             sysDevice.setCreateBy(username);
             sysDevice.setDeptId(deptId);
             sysDeviceMapper.insertSysDevice(sysDevice);
             }
             if (page < iotPage.getPages()){
             page ++;
             } else {
             break;
             }
             */

        }

        redisCache.setCacheObject(CacheConstants.SYNC_DEVICE,"false");
    }
    /**
     * 修改设备
     * 
     * @param sysDevice 设备
     * @return 结果
     */
    @Override
    public int updateSysDevice(SysDevice sysDevice)
    {
        sysDevice.setUpdateTime(DateUtils.getNowDate());
        return sysDeviceMapper.updateSysDevice(sysDevice);
    }

    /**
     * 绑定设备
     *
     * @param sysDevice 设备
     * @return 结果
     */
    @Override
    public int updateSysDeviceWithCode(SysDevice sysDevice){
        sysDevice.setUpdateTime(DateUtils.getNowDate());
        sysDevice.setRegisterTime(DateUtils.getNowDate());
        return sysDeviceMapper.updateSysDeviceWithCode(sysDevice);
    }

    /**
     * 批量删除设备
     * 
     * @param deviceIds 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteSysDeviceByDeviceIds(Long[] deviceIds)
    {
        return sysDeviceMapper.deleteSysDeviceByDeviceIds(deviceIds);
    }

    /**
     * 删除设备信息
     * 
     * @param deviceId 设备主键
     * @return 结果
     */
    @Override
    public int deleteSysDeviceByDeviceId(Long deviceId)
    {
        return sysDeviceMapper.deleteSysDeviceByDeviceId(deviceId);
    }

    /**
     * 统计开栓户数
     * @param deptId
     * @return
     */
    @Override
    public int useDevice(Long deptId){
        return sysDeviceMapper.useDevice(deptId);
    }

    /**
     * 统计面积
     * @param deptId
     * @return
     */
    @Override
    public BigDecimal selectArea(Long deptId){
        return sysDeviceMapper.selectArea(deptId);
    }

    /**
     * 统计小区的用户数、集中器数
     * @param deptId
     * @return
     */
    @Override
    public List<HouseDataBoard> houseList(Long deptId){
        return sysDeviceMapper.houseList(deptId);
    }

    /**
     * 统计每户的室温和累计热量
     */
    @Override
    public List<BuildingDataBoard> buildingList(Long deptId,Long houseId, String buildNo){
        Date now = DateUtils.getNowDate();
        String start = sysConfigService.selectConfigByKey("sys.rest.heatDate");
        String year = sysConfigService.selectConfigByKey("sys.heat.year");
        Date startDate = DateUtils.parseDate(year + "-" + start);
        return sysDeviceMapper.buildingList(deptId,houseId,buildNo,startDate,now);
    }

    /**
     * 更新设备开关阀状态
     */
    @Override
    public void updateDeviceStatus(DeviceCache deviceCache, ValueResult valueResult){
        SysDevice sysDevice = new SysDevice();
        sysDevice.setDeviceCode(valueResult.getNodeId());
        if (valueResult.getValveOpening() == 0 && deviceCache.getValveOpening() != 0) {
            sysDevice.setLockMode(IotConstants.SET_OPENING_IOT_VALUE_CLOSE);
            sysDeviceMapper.updateSysDeviceWithCode(sysDevice);
        }
        else if (valueResult.getValveOpening() > 0 && deviceCache.getValveOpening() == 0) {
            sysDevice.setLockMode(IotConstants.SET_OPENING_IOT_VALUE_OPEN);
            sysDeviceMapper.updateSysDeviceWithCode(sysDevice);
        }
    }
}
